home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C100.ZIP / KERMIT.ZIP / CKUTIO.C < prev    next >
Text File  |  1990-01-31  |  65KB  |  2,220 lines

  1. char *ckxv = "Unix tty I/O, 4E(047), 27 Jan 88";
  2.  
  3. /*  C K U T I O  */
  4.  
  5. /* C-Kermit interrupt, terminal control & i/o functions for Unix systems */
  6.  
  7. /*
  8.  Author: Frank da Cruz (SY.FDC@CU20B),
  9.  Columbia University Center for Computing Activities, January 1985.
  10.  Copyright (C) 1985, 1988, Trustees of Columbia University in the City of New
  11.  York.  Permission is granted to any individual or institution to use, copy, or
  12.  redistribute this software so long as it is not sold for profit, provided this
  13.  copyright notice is retained.
  14. */
  15. /* Includes for all Unixes (conditional includes come later) */
  16.  
  17. #include <sys/types.h>            /* Types */
  18.  
  19. #include <sys/dir.h>            /* Directory */
  20. #include <ctype.h>            /* Character types */
  21. #ifdef NULL
  22. #undef NULL
  23. #endif /* NULL */
  24. #include <stdio.h>            /* Unix Standard i/o */
  25. #include <signal.h>            /* Interrupts */
  26.  
  27. #ifndef ZILOG
  28. #include <setjmp.h>            /* Longjumps */
  29. #else
  30. #include <setret.h>
  31. #endif
  32.  
  33. #include "ckcdeb.h"            /* Typedefs, formats for debug() */
  34.  
  35. /* Maximum length for the name of a tty device */
  36.  
  37. #ifndef DEVNAMLEN
  38. #define DEVNAMLEN 25
  39. #endif
  40.  
  41. /* 4.1 BSD support added by Charles E. Brooks, EDN-VAX */
  42. /* Fortune 32:16 Pro:For 1.8 support mostly like 4.1, added by J-P Dumas */
  43.  
  44. #ifdef BSD4
  45. #define ANYBSD
  46. #ifdef MAXNAMLEN
  47. #define BSD42
  48. #ifdef aegis
  49. char *ckxsys = " Apollo DOMAIN/IX 4.2 BSD";
  50. #else
  51. char *ckxsys = " 4.2 BSD";
  52. #endif /* aegis */
  53. #else
  54. #ifdef FT18
  55. #define BSD41
  56. char *ckxsys = " Fortune For:Pro 1.8";
  57. #else
  58. #define BSD41
  59. #ifndef C70
  60. char *ckxsys = " 4.1 BSD";
  61. #endif /* not c70 */
  62. #endif /* ft18 */
  63. #endif /* maxnamlen */
  64. #endif /* bsd4 */
  65.  
  66. /* 2.9bsd support contributed by Bradley Smith, UCLA */
  67. #ifdef BSD29
  68. #define ANYBSD
  69. char *ckxsys = " 2.9 BSD";
  70. #endif /* bsd29 */
  71.  
  72. /*
  73.  Version 7 UNIX support contributed by Gregg Wonderly,
  74.  Oklahoma State University:  gregg@okstate.csnet
  75. */
  76. #ifdef    V7
  77. char *ckxsys = " Version 7 UNIX (tm)";
  78. #endif /* v7 */
  79.  
  80. /* BBN C70 support from Frank Wancho, WANCHO@SIMTEL20 */
  81. #ifdef C70
  82. char *ckxsys = " BBN C/70";
  83. #endif /* c70 */
  84.  
  85. /* IBM 370 IX/370 support from Wayne Van Pelt, GE/CRD, Schenectedy, NY */
  86. #ifdef IX370
  87. char *ckxsys = " IBM IX/370";
  88. #endif /* ix370 */
  89.  
  90. /* Amdahl UTS 2.4 (v7 derivative) for IBM 370 series compatible mainframes */
  91. /* Contributed by Garard Gaye, Jean-Pierre Dumas, DUMAS@SUMEX-AIM. */
  92. #ifdef UTS24
  93. char *ckxsys = " Amdahl UTS 2.4";
  94. #endif /* uts24 */
  95.  
  96. /* Pro/Venix Version 1.x support from Columbia U. */
  97. #ifdef PROVX1
  98. char *ckxsys = " Pro-3xx Venix v1";
  99. #endif /* provx1 */
  100.  
  101. /* Tower support contributed by John Bray, Auburn, Alabama */
  102. #ifdef TOWER1
  103. char *ckxsys = " NCR Tower 1632, OS 1.02";
  104. #endif /* tower1 */
  105.  
  106. /* Sys III/V, Xenix, PC/IX support by Herm Fischer, Encino, CA */
  107. #ifdef UXIII
  108. #ifdef XENIX
  109. char *ckxsys = " Xenix/286";
  110. #else
  111. #ifdef PCIX
  112. char *ckxsys = " PC/IX";
  113. #else
  114. #ifdef ISIII
  115. char *ckxsys = " Interactive Systems Corp System III";
  116. #else
  117. #ifdef hpux
  118. /* HP 9000 Series changes contributed by Bill Coalson */
  119. char *ckxsys = " HP 9000 Series HP-UX";
  120. #else
  121. #ifdef aegis
  122. /* Apollo Aegis support from SAS Institute, Cary, NC */
  123. char *ckxsys = " Apollo DOMAIN/IX System V";
  124. #else
  125. #ifdef ZILOG
  126. char *ckxsys = " Zilog S8000 Zeus 3.21+";
  127. #else
  128. #ifdef VXVE
  129. /* Control Data Corp VX/VE 5.2.1 System V support by */
  130. /* S.O. Lidie, Lehigh University, LUSOL@LEHICDC1.BITNET */
  131. char *ckxsys = " CDC VX/VE 5.2.1 System V";
  132. #else
  133. char *ckxsys = " AT&T System III/System V";
  134. #endif /* vxve  */
  135. #endif /* zilog */
  136. #endif /* aegis */
  137. #endif /* hpux  */
  138. #endif /* isiii */
  139. #endif /* pcix  */
  140. #endif /* xenix */
  141. #endif /* uxiii */
  142.  
  143. /* Features... */
  144.  
  145. /* Do own buffering, using unbuffered read() calls... */
  146. #ifdef UXIII
  147. #define MYREAD
  148. #endif /* uxiii */
  149.  
  150. #ifdef BSD42
  151. #undef MYREAD
  152. #include <errno.h>
  153. #endif /* bsd42 */
  154.  
  155. /*
  156.  Variables available to outside world:
  157.  
  158.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  159.    dfloc  -- 0 if dftty is console, 1 if external line.
  160.    dfprty -- Default parity
  161.    dfflow -- Default flow control
  162.    ckxech -- Flag for who echoes console typein:
  163.      1 - The program (system echo is turned off)
  164.      0 - The system (or front end, or terminal).
  165.    functions that want to do their own echoing should check this flag
  166.    before doing so.
  167.  
  168.    flfnam -- Name of lock file, including its path, e.g.,
  169.         "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
  170.    hasLock -- Flag set if this kermit established a uucp lock.
  171.    inbufc -- number of tty line rawmode unread characters
  172.         (system III/V unixes)
  173.    backgrd -- Flag indicating program executing in background ( & on
  174.         end of shell command). Used to ignore INT and QUIT signals.
  175.  
  176.  Functions for assigned communication line (either external or console tty):
  177.  
  178.    sysinit()               -- System dependent program initialization
  179.    syscleanup()            -- System dependent program shutdown
  180.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  181.    ttclos()                -- Close & reset the tty, releasing any access lock.
  182.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  183.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  184.                 or in DIALING or CONNECTED modem control state.
  185.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  186.    ttinc(timo)             -- Timed read character from tty.
  187.    myread()           -- System 3 raw mode bulk buffer read, gives
  188.                --   subsequent chars one at a time and simulates
  189.                --   FIONREAD!
  190.    myunrd(c)           -- Places c back in buffer to be read (one only)
  191.    ttchk()                 -- See how many characters in tty input buffer.
  192.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  193.    ttol(string,length)     -- Write a string to the tty.
  194.    ttoc(c)                 -- Write a character to the tty.
  195.    ttflui()                -- Flush tty input buffer.
  196.  
  197.    ttlock(ttname)       -- Lock against uucp collisions (Sys III)
  198.    ttunlck()           -- Unlock "       "     "
  199.    look4lk(ttname)       -- Check if a lock file exists
  200. */
  201.  
  202. /*
  203. Functions for console terminal:
  204.  
  205.    congm()   -- Get console terminal modes.
  206.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  207.    conbin(esc) -- Put the console in binary (raw) mode.
  208.    conres()  -- Restore the console to mode obtained by congm().
  209.    conoc(c)  -- Unbuffered output, one character to console.
  210.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  211.    conola(s) -- Unbuffered output, array of strings to the console.
  212.    conxo(n,s) -- Unbuffered output, n characters to the console.
  213.    conchk()  -- Check if characters available at console (bsd 4.2).
  214.         Check if escape char (^\) typed at console (System III/V).
  215.    coninc(timo)  -- Timed get a character from the console.
  216.    conint()  -- Enable terminal interrupts on the console if not background.
  217.    connoi()  -- Disable terminal interrupts on the console if not background.
  218.  
  219. Time functions
  220.  
  221.    msleep(m) -- Millisecond sleep
  222.    ztime(&s) -- Return pointer to date/time string
  223.    rtimer() --  Reset timer
  224.    gtimer()  -- Get elapsed time since last call to rtimer()
  225. */
  226.  
  227. /* Conditional Includes */
  228.  
  229. #ifdef FT18
  230. #include <sys/file.h>              /* File information */
  231. #endif /* ft18 */
  232.  
  233. /* Whether to #include <sys/file.h>... */
  234. #ifndef PROVX1
  235. #ifndef aegis
  236. #ifndef XENIX
  237. #include <sys/file.h>              /* File information */
  238. #endif /* xenix */
  239. #endif /* aegis */
  240. #endif /* provx1 */
  241.  
  242. #ifdef aegis
  243. #ifdef BSD4
  244. #include <sys/file.h>
  245. #include <fcntl.h>
  246. #endif /* bsd4 */
  247. #endif /* aegis */
  248.  
  249. /* System III, System V */
  250.  
  251. #ifdef UXIII
  252. #include <termio.h>
  253. #include <sys/ioctl.h>
  254. #include <fcntl.h>            /* directory reading for locking */
  255. #include <errno.h>            /* error numbers for system returns */
  256. #endif /* uxiii */
  257.  
  258. #ifdef HPUX
  259. #include <sys/modem.h>
  260. #endif
  261.  
  262. /* Not Sys III/V */
  263.  
  264. #ifndef UXIII
  265. #include <sgtty.h>            /* Set/Get tty modes */
  266. #ifndef PROVX1
  267. #ifndef V7
  268. #ifndef BSD41
  269. #include <sys/time.h>            /* Clock info (for break generation) */
  270. #endif /* not bsd41 */
  271. #endif /* not v7 */
  272. #endif /* not provx1 */
  273. #endif /* not uxiii */
  274.  
  275. #ifdef BSD41
  276. #include <sys/timeb.h>            /* BSD 4.1 ... ceb */
  277. #endif /* bsd41 */
  278.  
  279. #ifdef BSD29
  280. #include <sys/timeb.h>            /* BSD 2.9 (Vic Abell, Purdue) */
  281. #endif /* bsd29 */
  282.  
  283. #ifdef TOWER1
  284. #include <sys/timeb.h>            /* Clock info for NCR Tower */
  285. #endif /* tower1 */
  286.  
  287. #ifdef aegis
  288. #include "/sys/ins/base.ins.c"
  289. #include "/sys/ins/error.ins.c"
  290. #include "/sys/ins/ios.ins.c"
  291. #include "/sys/ins/sio.ins.c"
  292. #include "/sys/ins/pad.ins.c"
  293. #include "/sys/ins/time.ins.c"
  294. #include "/sys/ins/pfm.ins.c"
  295. #include "/sys/ins/pgm.ins.c"
  296. #include "/sys/ins/ec2.ins.c"
  297. #include "/sys/ins/type_uids.ins.c"
  298. #include <default_acl.h>
  299. #undef TIOCEXCL
  300. #undef FIONREAD
  301. #endif
  302.  
  303. /* The following two conditional #defines are catch-alls for those systems */
  304. /* that didn't have or couldn't find <file.h>... */
  305.  
  306. #ifndef FREAD
  307. #define FREAD 0x01
  308. #endif
  309.  
  310. #ifndef FWRITE
  311. #define FWRITE 0x10
  312. #endif
  313.  
  314. /* Declarations */
  315.  
  316. long time();                /* All Unixes should have this... */
  317. extern int errno;            /* System call error code. */
  318.  
  319. /* Special stuff for V7 input buffer peeking */
  320.  
  321. #ifdef    V7
  322. int kmem[2] = { -1, -1};
  323. char *initrawq(), *qaddr[2]={0,0};
  324. #define CON 0
  325. #define TTY 1
  326. #endif /* v7 */
  327.  
  328. /* dftty is the device name of the default device for file transfer */
  329. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  330.  
  331. #ifdef PROVX1
  332.     char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
  333.     int dfloc = 1;            /* that goes in local mode by default */
  334. #else
  335.     char *dftty = CTTNAM;        /* Remote by default, use normal */
  336.     int dfloc = 0;            /* controlling terminal name. */
  337. #endif /* provx1 */
  338.  
  339.     int dfprty = 0;            /* Default parity (0 = none) */
  340.     int ttprty = 0;            /* Parity in use. */
  341.     int ttmdm = 0;            /* Modem in use. */
  342.     int dfflow = 1;            /* Xon/Xoff flow control */
  343.     int backgrd = 0;            /* Assume in foreground (no '&' ) */
  344.  
  345. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  346.  
  347. /* Declarations of variables global within this module */
  348.  
  349. static long tcount;            /* Elapsed time counter */
  350.  
  351. static char *brnuls = "\0\0\0\0\0\0\0"; /* A string of nulls */
  352.  
  353. static jmp_buf sjbuf, jjbuf;        /* Longjump buffer */
  354. static int lkf = 0,            /* Line lock flag */
  355.     conif = 0,                /* Console interrupts on/off flag */
  356.     cgmf = 0,                /* Flag that console modes saved */
  357.     xlocal = 0,                /* Flag for tty local or remote */
  358.     ttyfd = -1;                /* TTY file descriptor */
  359. static char escchr;            /* Escape or attn character */
  360.  
  361. #ifdef BSD42
  362.     static struct timeval tv;        /* For getting time, from sys/time.h */
  363.     static struct timezone tz;
  364. #endif /* bsd42 */
  365.  
  366. #ifdef BSD29
  367.     static long clock;            /* For getting time from sys/time.h */
  368.     static struct timeb ftp;        /* And from sys/timeb.h */
  369. #endif /* bsd29 */
  370.  
  371. #ifdef BSD41
  372.     static long clock;            /* For getting time from sys/time.h */
  373.     static struct timeb ftp;        /* And from sys/timeb.h */
  374. #endif /* bsd41 */
  375.  
  376. #ifdef TOWER1
  377. static long clock;            /* For getting time from sys/time.h */
  378. static struct timeb ftp;        /* And from sys/timeb.h */
  379. #endif /* tower1 */
  380.  
  381. #ifdef V7
  382. static long clock;
  383. #endif /* v7 */
  384.  
  385. /* sgtty/termio information... */
  386.  
  387. #ifdef UXIII
  388.   static struct termio ttold = {0};    /* Init'd for word alignment, */
  389.   static struct termio ttraw = {0};    /* which is important for some */
  390.   static struct termio tttvt = {0};    /* systems, like Zilog... */
  391.   static struct termio ccold = {0};
  392.   static struct termio ccraw = {0};
  393.   static struct termio cccbrk = {0};
  394. #else
  395.   static struct sgttyb             /* sgtty info... */
  396.     ttold, ttraw, tttvt, ttbuf,        /* for communication line */
  397.     ccold, ccraw, cccbrk;        /* and for console */
  398. #endif /* uxiii */
  399.  
  400. static char flfnam[80];            /* uucp lock file path name */
  401. static int hasLock = 0;            /* =1 if this kermit locked uucp */
  402. static int inbufc = 0;            /* stuff for efficient SIII raw line */
  403. static int ungotn = -1;            /* pushback to unread character */
  404. static int conesc = 0;            /* set to 1 if esc char (^\) typed */
  405.  
  406. static int ttlock();            /* definition of ttlock subprocedure */
  407. static int ttunlck();            /* and unlock subprocedure */
  408. static char ttnmsv[DEVNAMLEN];        /* copy of open path for tthang */
  409.  
  410. #ifdef aegis
  411. static status_$t st;            /* error status return value */
  412. static short concrp = 0;         /* true if console is CRP pad */
  413. #define CONBUFSIZ 10
  414. static char conbuf[CONBUFSIZ];        /* console readahead buffer */
  415. static int  conbufn = 0;        /* # chars in readahead buffer */
  416. static char *conbufp;            /* next char in readahead buffer */
  417. static uid_$t ttyuid;            /* tty type uid */
  418. static uid_$t conuid;            /* stdout type uid */
  419.  
  420. /* APOLLO Aegis main()
  421.  * establish acl usage and cleanup handling
  422.  *    this makes sure that CRP pads
  423.  *    get restored to a usable mode
  424.  */
  425. main(argc,argv) int argc; char **argv; {
  426.     status_$t status;
  427.     pfm_$cleanup_rec dirty;
  428.  
  429.     int pid = getpid();
  430.  
  431.     /* acl usage according to invoking environment */
  432.     default_acl(USE_DEFENV);
  433.  
  434.     /* establish a cleanup continuation */
  435.     status = pfm_$cleanup(dirty);
  436.     if (status.all != pfm_$cleanup_set)
  437.     {
  438.         /* only handle faults for the original process */
  439.         if (pid == getpid() && status.all > pgm_$max_severity)
  440.         {    /* blew up in main process */
  441.             status_$t quo;
  442.             pfm_$cleanup_rec clean;
  443.  
  444.             /* restore the console in any case */
  445.             conres();
  446.  
  447.             /* attempt a clean exit */
  448.             debug(F101, "cleanup fault status", "", status.all);
  449.  
  450.             /* doexit(), then send status to continuation */
  451.             quo = pfm_$cleanup(clean);
  452.             if (quo.all == pfm_$cleanup_set)
  453.                 doexit(pgm_$program_faulted);
  454.             else if (quo.all > pgm_$max_severity)
  455.                 pfm_$signal(quo); /* blew up in doexit() */
  456.         }
  457.         /* send to the original continuation */
  458.         pfm_$signal(status);
  459.         /*NOTREACHED*/
  460.     }
  461.     return(ckcmai(argc, argv));
  462. }
  463. #endif /* aegis */
  464.  
  465. /*  S Y S I N I T  --  System-dependent program initialization.  */
  466.  
  467. sysinit() {
  468.  
  469. /* for now, nothing... */
  470.     return(0);
  471. }
  472.  
  473. /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
  474.  
  475. syscleanup() {
  476.  
  477. /* for now, nothing... */
  478.     return(0);
  479. }
  480.  
  481. /*  T T O P E N  --  Open a tty for exclusive access.  */
  482.  
  483. /*  Returns 0 on success, -1 on failure.  */
  484. /*
  485.   If called with lcl < 0, sets value of lcl as follows:
  486.   0: the terminal named by ttname is the job's controlling terminal.
  487.   1: the terminal named by ttname is not the job's controlling terminal.
  488.   But watch out: if a line is already open, or if requested line can't
  489.   be opened, then lcl remains (and is returned as) -1.
  490. */
  491. ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  492.  
  493. #ifdef UXIII
  494. #ifndef CIE
  495.     char *ctermid();            /* Wish they all had this! */
  496. #endif /* not cie */
  497. #endif /* uxiii */
  498.  
  499. #ifdef CIE                /* CIE Regulus doesn't... */
  500. #define ctermid(x) strcpy(x,"")
  501. #endif
  502.  
  503.     char *x; extern char* ttyname();
  504.     char cname[DEVNAMLEN+4];
  505.  
  506.     if (ttyfd > -1) return(0);        /* If already open, ignore this call */
  507.     ttmdm = modem;            /* Make this available to other fns */
  508.     xlocal = *lcl;            /* Make this available to other fns */
  509. #ifdef NEWUUCP
  510.     acucntrl("disable",ttname);        /* Open getty on line (4.3BSD) */
  511. #endif /* newuucp */
  512. #ifdef UXIII
  513.     /* if modem connection, don't wait for carrier */
  514.     ttyfd = open(ttname,O_RDWR | (modem ? O_NDELAY : 0) );
  515. #else
  516.     ttyfd = open(ttname,2);        /* Try to open for read/write */
  517. #endif /* uxiii */
  518.  
  519.     if (ttyfd < 0) {            /* If couldn't open, fail. */
  520.     perror(ttname);
  521.     return(-1);
  522.     }
  523. #ifdef aegis
  524.     /* Apollo C runtime claims that console pads are tty devices, which
  525.      * is reasonable, but they aren't any good for packet transfer. */
  526.     ios_$inq_type_uid((short)ttyfd, ttyuid, st);
  527.     if (st.all != status_$ok) {
  528.     fprintf(stderr, "problem getting tty object type: ");
  529.     error_$print(st);
  530.     } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
  531.     close(ttyfd); ttyfd = -1;
  532.     errno = ENOTTY; perror(ttname);
  533.     return(-1);
  534.     }
  535. #endif /* aegis */
  536.     strncpy(ttnmsv,ttname,DEVNAMLEN);    /* Open, keep copy of name locally. */
  537.  
  538. /* Caller wants us to figure out if line is controlling tty */
  539.  
  540.     debug(F111,"ttopen ok",ttname,*lcl);
  541.     if (*lcl == -1) {
  542.     if (strcmp(ttname,CTTNAM) == 0) {   /* "/dev/tty" always remote */
  543.         debug(F110," Same as CTTNAM",ttname,0);
  544.         xlocal = 0;
  545.     } else if (isatty(0)) {        /* Else, if stdin not redirected */
  546.         x = ttyname(0);        /* then compare its device name */
  547.         strncpy(cname,x,DEVNAMLEN);    /* (copy from internal static buf) */
  548.         debug(F110," ttyname(0)",x,0);
  549.         x = ttyname(ttyfd);     /* ...with real name of ttname. */
  550.         xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
  551.         debug(F111," ttyname",x,xlocal);
  552.     } else {            /* Else, if stdin redirected... */
  553. #ifdef UXIII
  554. /* Sys III/V provides nice ctermid() function to get name of controlling tty */
  555.             ctermid(cname);        /* Get name of controlling terminal */
  556.         debug(F110," ctermid",cname,0);
  557.         x = ttyname(ttyfd);     /* Compare with name of comm line. */
  558.         xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
  559.         debug(F111," ttyname",x,xlocal);
  560. #else
  561. /* Just assume local, so "set speed" and similar commands will work */
  562. /* If not really local, how could it work anyway?... */
  563.         xlocal = 1;
  564.         debug(F101," redirected stdin","",xlocal);
  565. #endif /* uxiii */
  566.         }
  567.     }
  568.  
  569. /* Now check if line is locked -- if so fail, else lock for ourselves */
  570.  
  571.     lkf = 0;                /* Check lock */
  572.     if (xlocal > 0) {
  573.     if (ttlock(ttname) < 0) {
  574.         fprintf(stderr,"Exclusive access to %s denied\n",ttname);
  575.         close(ttyfd); ttyfd = -1;
  576.         debug(F110," Access denied by lock",ttname,0);
  577.         return(-1);            /* Not if already locked */
  578.         } else lkf = 1;
  579.     }
  580.  
  581. /* Got the line, now set the desired value for local. */
  582.  
  583.     if (*lcl < 0) *lcl = xlocal;
  584.  
  585. /* Some special stuff for v7... */
  586.  
  587. #ifdef    V7
  588.     if (kmem[TTY] < 0) {    /*  If open, then skip this.  */
  589.         qaddr[TTY] = initrawq(ttyfd);    /* Init the queue. */
  590.         if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
  591.             fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
  592.             perror("/dev/kmem");
  593.             exit(1);
  594.         }
  595.     }
  596. #endif /* v7 */
  597.  
  598. /* Request exclusive access on systems that allow it. */
  599.  
  600. #ifndef XENIX
  601. /* Xenix exclusive access prevents open(close(...)) from working... */
  602. #ifdef TIOCEXCL
  603.         if (ioctl(ttyfd,TIOCEXCL, NULL) < 0)
  604.         fprintf(stderr,"Warning, problem getting exclusive access\n");
  605. #endif /* tiocexcl */
  606. #endif /* xenix */
  607.  
  608. /* Get tty device settings */
  609.  
  610. #ifndef UXIII
  611.     gtty(ttyfd,&ttold);            /* Get sgtty info */
  612. #ifdef aegis
  613.     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
  614.     if (xlocal) {    /* ignore breaks from local line */
  615.     sio_$control((short)ttyfd, sio_$int_enable, false, st);
  616.     sio_$control((short)ttyfd, sio_$quit_enable, false, st);
  617.     }
  618. #endif /* aegis */
  619.     gtty(ttyfd,&ttraw);            /* And a copy of it for packets*/
  620.     gtty(ttyfd,&tttvt);            /* And one for virtual tty service */
  621. #else
  622.     ioctl(ttyfd,TCGETA,&ttold);        /* Same deal for Sys III, Sys V */
  623. #ifdef aegis
  624.     sio_$control((short)ttyfd, sio_$raw_nl, false, st);
  625.     if (xlocal) {    /* ignore breaks from local line */
  626.     sio_$control((short)ttyfd, sio_$int_enable, false, st);
  627.     sio_$control((short)ttyfd, sio_$quit_enable, false, st);
  628.     }
  629. #endif /* aegis */
  630.     ioctl(ttyfd,TCGETA,&ttraw);
  631.     ioctl(ttyfd,TCGETA,&tttvt);
  632. #endif /* not uxiii */
  633.  
  634. #ifdef VXVE
  635.     ttraw.c_line = 0;            /* STTY line 0 for VX/VE */
  636.     ioctl(ttyfd,TCSETA,&ttraw);
  637.     tttvt.c_line = 0;            /* STTY line 0 for VX/VE */
  638.     ioctl(ttyfd,TCSETA,&tttvt);
  639. #endif /* vxve */
  640.  
  641.     debug(F101,"ttopen, ttyfd","",ttyfd);
  642.     debug(F101," lcl","",*lcl);
  643.     debug(F111," lock file",flfnam,lkf);
  644.     return(0);
  645. }
  646.  
  647. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  648.  
  649. ttclos() {
  650.     if (ttyfd < 0) return(0);        /* Wasn't open. */
  651.     if (xlocal) {
  652.     if (tthang())            /* Hang up phone line */
  653.         fprintf(stderr,"Warning, problem hanging up the phone\n");
  654.         if (ttunlck())            /* Release uucp-style lock */
  655.         fprintf(stderr,"Warning, problem releasing lock\n");
  656.     }
  657.     ttres();                /* Reset modes. */
  658. /* Relinquish exclusive access if we might have had it... */
  659. #ifndef XENIX
  660. #ifdef TIOCEXCL
  661. #ifdef TIOCNXCL
  662.     if (ioctl(ttyfd, TIOCNXCL, NULL) < 0)
  663.         fprintf(stderr,"Warning, problem relinquishing exclusive access\n");
  664. #endif /* tiocnxcl */
  665. #endif /* tiocexcl */
  666. #endif /* not xenix */
  667.     close(ttyfd);            /* Close it. */
  668. #ifdef NEWUUCP
  669.     acucntrl("enable",flfnam);        /* Close getty on line. */
  670. #endif /* newuucp */
  671.     ttyfd = -1;                /* Mark it as closed. */
  672.     return(0);
  673. }
  674.  
  675. /*  T T H A N G -- Hangup phone line */
  676.  
  677. tthang() {
  678. #ifdef UXIII
  679. #ifdef HPUX
  680.     unsigned long dtr_down = 00000000000,
  681.                   modem_rtn;
  682. #else
  683.     unsigned short ttc_save;
  684. #endif /* hpux */
  685. #endif /* uxiii */
  686.  
  687.     if (ttyfd < 0) return(0);        /* Not open. */
  688. #ifdef aegis
  689.     sio_$control((short)ttyfd, sio_$dtr, false, st);    /* DTR down */
  690.     msleep(500);                    /* pause */
  691.     sio_$control((short)ttyfd, sio_$dtr, true,  st);    /* DTR up */
  692. #else
  693. #ifdef ANYBSD
  694.     ioctl(ttyfd,TIOCCDTR,0);        /* Clear DTR */
  695.     msleep(500);            /* Let things settle */
  696.     ioctl(ttyfd,TIOCSDTR,0);        /* Restore DTR */
  697. #endif /* anybsd */
  698. #ifdef UXIII
  699. #ifdef HPUX   /* Hewlett Packard way of modem control  */
  700.     if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) return(-1); /* lower DTR */
  701.     msleep(500);
  702.     if (ioctl(ttyfd,MCGETA,&modem_rtn) < 0) return(-1); /* get line status */
  703.     if ((modem_rtn & MDCD) != 0) return(-1);        /* check if DCD is low */
  704.     modem_rtn = MRTS | MDTR;                        /* bits for RTS & DTR  */
  705.     if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) return(-1);    /*  set lines  */
  706. #else
  707.     ttc_save = ttraw.c_cflag;
  708.     ttraw.c_cflag &= ~CBAUD;        /* swa: set baud rate to 0 to hangup */
  709.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* do it */
  710.     msleep(100);            /* let things settle */
  711.     ttraw.c_cflag = ttc_save;
  712.  
  713. /* NOTE - The following #ifndef...#endif can be removed for SCO Xenix 2.1.3 */
  714. /* or later, but must keep for earlier versions, which can't do close/open. */
  715.  
  716. #ifndef XENIX        /* xenix cannot do close/open when carrier drops */
  717.                 /* following corrects a PC/IX defficiency */
  718.     ttc_save = fcntl(ttyfd,F_GETFL,0);
  719.     close(ttyfd);        /* close/reopen file descriptor */
  720.     if ((ttyfd = open(ttnmsv, ttc_save)) < 0) return(-1);
  721. #endif /* not xenix */
  722.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* un-do it */
  723. #endif /* uxiii */
  724. #endif /* hpux  */
  725. #endif /* aegis */
  726.     return (0);
  727. }
  728.  
  729.  
  730. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  731.  
  732. ttres() {                /* Restore the tty to normal. */
  733.     int x;
  734.  
  735.     if (ttyfd < 0) return(-1);        /* Not open. */
  736. #ifndef UXIII                /* except for sIII, */
  737.     sleep(1);                /* Wait for pending i/o to finish. */
  738. #endif    /* uxiii */            /*   (sIII does wait in ioctls) */
  739.  
  740. #ifdef UXIII
  741.     if (ioctl(ttyfd,TCSETAW,&ttold) < 0) return(-1); /* restore termio stuff */
  742.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  743.       return(-1);
  744. #else /* not uxiii */
  745. #ifdef FIONBIO
  746.     x = 0;
  747.     x = ioctl(ttyfd,FIONBIO,&x);
  748.     if (x < 0) {
  749.     perror("ttres ioctl");
  750.     debug(F101,"ttres ioctl","",x);
  751.     }
  752. #else /* not fionbio */
  753. #ifdef FNDELAY
  754.     x = (fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL,0) & ~FNDELAY) == -1);
  755.     debug(F101,"ttres fcntl","",x);
  756.     if (x < 0) perror("fcntl");
  757. #endif /* fndelay */
  758. #endif /* fionbio */
  759.     x = stty(ttyfd,&ttold);        /* Restore sgtty stuff */
  760.     debug(F101,"ttres stty","",x);
  761.     if (x < 0) perror("stty");
  762. #endif /* uxiii */
  763.     return(x);
  764. }
  765.  
  766. /* Exclusive uucp file locking control */
  767. /*
  768.  by H. Fischer, creative non-Bell coding !
  769.  copyright rights for lock modules assigned to Columbia University
  770. */
  771. static char *
  772. xxlast(s,c) char *s; char c; {        /* Equivalent to strrchr() */
  773.     int i;
  774.     for (i = strlen(s); i > 0; i--)
  775.         if ( s[i-1] == c ) return( s + (i - 1) );
  776.     return(NULL);
  777. }
  778. static
  779. look4lk(ttname) char *ttname; {
  780.     extern char *strcat(), *strcpy();
  781.     char *device, *devname;
  782.     char lockfil[50];            /* Max length for lock file name */
  783.  
  784. #ifdef ISIII
  785.     char *lockdir = "/etc/locks";
  786. #else
  787. #ifdef ATT3BX
  788.     char *lockdir = "/usr/spool/locks";
  789. #else
  790. #ifdef NEWUUCP
  791.     char *lockdir = "/usr/spool/uucp/LCK";
  792. #else
  793.     char *lockdir = "/usr/spool/uucp";
  794. #endif /* newuucp */
  795. #endif /* att3bx */
  796. #endif /* isiii */
  797.  
  798.     device = ( (devname=xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  799.  
  800. #ifdef ISIII
  801.     (void) strcpy( lockfil, device );
  802. #else
  803.     strcat( strcpy( lockfil, "LCK.." ), device );
  804. #endif /* isiii */
  805.  
  806.     if (access( lockdir, 04 ) < 0) {    /* read access denied on lock dir */
  807.     fprintf(stderr,"Warning, read access to lock directory denied\n");
  808.     return( 1 );            /* cannot check or set lock file */
  809.     }
  810.     
  811.     strcat(strcat(strcpy(flfnam,lockdir),"/"), lockfil);
  812.     debug(F110,"look4lk",flfnam,0);
  813.  
  814.     if ( ! access( flfnam, 00 ) ) {    /* print out lock file entry */
  815.     char lckcmd[40] ;
  816.     strcat( strcpy(lckcmd, "ls -l ") , flfnam);
  817.     system(lckcmd);
  818.     if (access(flfnam,02) == 0)
  819.         printf("(You may type \"! rm %s\" to remove this file)\n",flfnam);
  820.     return( -1 );
  821.     }
  822.     if ( access( lockdir, 02 ) < 0 ) {    /* lock file cannot be written */
  823.     fprintf(stderr,"Warning, write access to lock directory denied\n");
  824.     return( 1 );
  825.     }
  826.     return( 0 );            /* okay to go ahead and lock */
  827. }
  828.  
  829. /*  T T L O C K  */
  830.  
  831. static
  832. ttlock(ttfd) char *ttfd; {        /* lock uucp if possible */
  833. #ifndef aegis
  834. #ifdef ATT3BX
  835.     FILE *lck_fild;
  836. #endif /* att3bx */
  837.     int lck_fil, l4l;
  838.     int pid_buf = getpid();        /* pid to save in lock file */
  839.     
  840.     hasLock = 0;            /* not locked yet */
  841.     l4l = look4lk(ttfd);
  842.     if (l4l < 0) return (-1);        /* already locked */
  843.     if (l4l == 1) return (0);        /* can't read/write lock directory */
  844.     lck_fil = creat(flfnam, 0444);    /* create lock file ... */
  845.     if (lck_fil < 0) return (-1);    /* create of lockfile failed */
  846.         /* creat leaves file handle open for writing -- hf */
  847. #ifdef ATT3BX
  848.     fprintf((lck_fild = fdopen(lck_fil, "w")), "%10d\n", pid_buf);
  849.     fflush(lck_fild);
  850. #else
  851.     write (lck_fil, &pid_buf, sizeof(pid_buf) ); /* uucp expects int in file */
  852. #endif /* att3bx */
  853.     close (lck_fil);
  854.     hasLock = 1;            /* now is locked */
  855. #endif /* not aegis */
  856.     return(0);
  857. }
  858.  
  859. /*  T T U N L O C K  */
  860.  
  861. static
  862. ttunlck() {                /* kill uucp lock if possible */
  863.     if (hasLock) return( unlink( flfnam ) );
  864.     return(0);
  865. }
  866.  
  867. /* New-style (4.3BSD) UUCP line direction control (Stan Barber, Rice U) */
  868.  
  869. #ifdef NEWUUCP
  870. acucntrl(flag,ttname) char *flag, *ttname; {
  871.     char x[DEVNAMLEN+32], *device, *devname;
  872.  
  873.     if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
  874.         return;                /* just return. */
  875.     device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  876.     if (strncmp(device,"LCK..",4) == 0) device += 5;
  877.     sprintf(x,"/usr/lib/uucp/acucntrl %s %s",flag,device);
  878.     debug(F000,"called ",x,0);
  879.     system(x);
  880. }
  881. #endif /* newuucp */
  882.  
  883. /*  T T P K T  --  Condition the communication line for packets. */
  884. /*        or for modem dialing */
  885.  
  886. #define DIALING    4        /* flags (via flow) for modem handling */
  887. #define CONNECT 5
  888.  
  889. /*  If called with speed > -1, also set the speed.  */
  890.  
  891. /*  Returns 0 on success, -1 on failure.  */
  892.  
  893. ttpkt(speed,flow,parity) int speed, flow, parity; {
  894.     int s, x;
  895.  
  896.     if (ttyfd < 0) return(-1);        /* Not open. */
  897.     ttprty = parity;            /* Let other tt functions see this. */
  898.     debug(F101,"ttpkt setting ttprty","",ttprty);
  899.     s = ttsspd(speed);            /* Check the speed */
  900.  
  901. #ifndef UXIII
  902.     if (flow == 1) ttraw.sg_flags |= TANDEM; /* Use XON/XOFF if selected */
  903.     if (flow == 0) ttraw.sg_flags &= ~TANDEM;
  904.     ttraw.sg_flags |= RAW;        /* Go into raw mode */
  905.     ttraw.sg_flags &= ~(ECHO|CRMOD);    /* Use CR for break character */
  906. #ifdef TOWER1
  907.     ttraw.sg_flags &= ~ANYP;         /* Must tell Tower no parity */
  908. #endif /* tower1 */
  909.     if (s > -1) ttraw.sg_ispeed = ttraw.sg_ospeed = s; /* Do the speed */
  910.     if (stty(ttyfd,&ttraw) < 0) return(-1);    /* Set the new modes. */
  911.  
  912. #ifdef MYREAD
  913. #ifdef BSD4
  914. /* Try to make reads nonblocking */
  915. #ifdef aegis
  916.     return(0);
  917. #endif /* aegis */
  918. #ifdef FIONBIO
  919.     x = 1;
  920.     if (ioctl(ttyfd,FIONBIO,&x) < 0) {
  921.     perror("ttpkt ioctl");
  922.     return(-1);
  923.     }
  924. #else /* fionbio */
  925. #ifdef FNDELAY
  926.     if (fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL,0) | FNDELAY) == -1) {
  927.     return(-1);
  928.     }
  929. #endif /* fndelay */
  930. #endif /* bsd4 */
  931.     ttflui();                /* Flush any pending input */
  932.     return(0);
  933. #endif /* bsd4 */
  934. #else  /* myread */
  935.     ttflui();                /* Flush any pending input */
  936.     return(0);
  937. #endif /* myread */
  938. #endif /* not uxiii */
  939.  
  940. #ifdef UXIII
  941.     if (flow == 1) ttraw.c_iflag |= (IXON|IXOFF);
  942.     if (flow == 0) ttraw.c_iflag &= ~(IXON|IXOFF);
  943.  
  944.     if (flow == DIALING)  ttraw.c_cflag |= CLOCAL|HUPCL;
  945.     if (flow == CONNECT)  ttraw.c_cflag &= ~CLOCAL;
  946.  
  947.     ttraw.c_lflag &= ~(ICANON|ECHO);
  948.     ttraw.c_lflag |= ISIG;        /* do check for interrupt */
  949.     ttraw.c_iflag |= (BRKINT|IGNPAR);
  950.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
  951.     ttraw.c_oflag &= ~OPOST;
  952.     ttraw.c_cflag &= ~(CSIZE|PARENB);
  953.     ttraw.c_cflag |= (CS8|CREAD);
  954. #ifdef IX370
  955.     ttraw.c_cc[4] = 48;     /* So Series/1 doesn't interrupt on every char */
  956.     ttraw.c_cc[5] = 1;
  957. #else
  958. #ifdef VXVE
  959.     ttraw.c_cc[4] = 1;   /* [VMIN]  for CDC VX/VE */
  960.     ttraw.c_cc[5] = 0;   /* [VTIME] for CDC VX/VE */
  961. #else
  962. #ifdef MYREAD
  963.     ttraw.c_cc[4] = 200; /* return max of this many characters */
  964.     ttraw.c_cc[5] = 1;   /* or when this many secs/10 expire w/no input */
  965. #else
  966.     ttraw.c_cc[4] = 1;   /* [VMIN]  Maybe should be bigger for all Sys V? */
  967.     ttraw.c_cc[5] = 0;   /* [VTIME] Should be set high enough to ignore */
  968.                     /* intercharacter spacing? */
  969.     /* But then we have to distinguish between Sys III and Sys V.. */
  970. #endif
  971. #endif
  972. #endif
  973.     if (s > -1) {            /* set speed */
  974.         ttraw.c_cflag &= ~CBAUD;
  975.     ttraw.c_cflag |= s;
  976.     }
  977.     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1);  /* set new modes . */
  978.     if (flow == DIALING) {
  979. #ifndef aegis
  980.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  981.         return(-1);
  982. #endif /* not aegis */
  983.     close( open(ttnmsv,2) );    /* magic to force mode change!!! */
  984.     }
  985.     ttflui();
  986.     return(0);
  987. #endif /* uxiii */
  988. }
  989.  
  990. /*  T T V T -- Condition communication line for use as virtual terminal  */
  991.  
  992. ttvt(speed,flow) int speed, flow; {
  993.     int s;
  994.     if (ttyfd < 0) return(-1);        /* Not open. */
  995.  
  996.     s = ttsspd(speed);            /* Check the speed */
  997.  
  998. #ifndef UXIII
  999.     if (flow == 1) tttvt.sg_flags |= TANDEM; /* XON/XOFF if selected */
  1000.     if (flow == 0) tttvt.sg_flags &= ~TANDEM;
  1001.     tttvt.sg_flags |= RAW;        /* Raw mode */
  1002. #ifdef TOWER1
  1003.     tttvt.sg_flags &= ~(ECHO|ANYP);    /* No echo or system III ??? parity */
  1004. #else
  1005.     tttvt.sg_flags &= ~ECHO;        /* No echo */
  1006. #endif
  1007.     if (s > -1) tttvt.sg_ispeed = tttvt.sg_ospeed = s; /* Do the speed */
  1008.     if (stty(ttyfd,&tttvt) < 0) return(-1);
  1009.  
  1010. #ifdef MYREAD
  1011. #ifdef BSD4
  1012. /* Make reads nonblocking */
  1013. #ifdef aegis
  1014.     return(0);
  1015. #endif
  1016.     if (fcntl(ttyfd,F_SETFL,fcntl(ttyfd,F_GETFL,0) | FNDELAY) == -1)
  1017.         return(-1);
  1018.     else return(0);
  1019. #endif /* bsd4 */
  1020. #endif /* myread */
  1021.  
  1022. #else /* uxiii */
  1023.     if (flow == 1) tttvt.c_iflag |= (IXON|IXOFF);
  1024.     if (flow == 0) tttvt.c_iflag &= ~(IXON|IXOFF);
  1025.  
  1026.     if (flow == DIALING)  tttvt.c_cflag |= CLOCAL|HUPCL;
  1027.     if (flow == CONNECT)  tttvt.c_cflag &= ~CLOCAL;
  1028.  
  1029.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
  1030.     tttvt.c_iflag |= (IGNBRK|IGNPAR);
  1031.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY);
  1032.     tttvt.c_oflag &= ~OPOST;
  1033.     tttvt.c_cflag &= ~(CSIZE|PARENB);
  1034.     tttvt.c_cflag |= (CS8|CREAD);
  1035.     tttvt.c_cc[4] = 1;
  1036.     tttvt.c_cc[5] = 0;
  1037.  
  1038.     if (s > -1) {            /* set speed */
  1039.     tttvt.c_cflag &= ~CBAUD;
  1040.     tttvt.c_cflag |= s;
  1041.     }
  1042.     if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1);  /* set new modes . */
  1043.  
  1044.     if (flow == DIALING) {
  1045. #ifndef aegis
  1046.     if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  1047.         return(-1);
  1048. #endif
  1049.     close( open(ttnmsv,2) );    /* magic to force mode change!!! */
  1050.     }
  1051. #endif
  1052.     return(0);
  1053. }
  1054.  
  1055. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  1056.  
  1057. ttsspd(speed) {
  1058.     int s, spdok;
  1059.  
  1060.     if (speed < 0) return(-1);
  1061.     spdok = 1;            /* Assume arg ok */
  1062.     switch (speed) {
  1063.         case 0:    s = B0;    break;    /* Just the common ones. */
  1064.         case 110:  s = B110;  break;    /* The others from ttydev.h */
  1065.         case 150:  s = B150;  break;    /* could also be included if */
  1066.         case 300:  s = B300;  break;    /* necessary... */
  1067.         case 600:  s = B600;  break;
  1068.         case 1200: s = B1200; break;
  1069.         case 1800: s = B1800; break;
  1070.         case 2400: s = B2400; break;
  1071.         case 4800: s = B4800; break;
  1072.         case 9600: s = B9600; break;
  1073. #ifdef PLEXUS
  1074.         case 19200: s = EXTA; break;
  1075. #endif
  1076. #ifdef aegis
  1077.         case 19200: s = EXTA; break;
  1078. #endif
  1079.         default:
  1080.             spdok = 0;
  1081.         fprintf(stderr,"Unsupported line speed - %d\n",speed);
  1082.         fprintf(stderr,"Current speed not changed\n");
  1083.         break;
  1084.     }
  1085.     if (spdok) return(s); else return(-1);
  1086.  }
  1087.  
  1088. /*  T T F L U I  --  Flush tty input buffer */
  1089.  
  1090. ttflui() {
  1091.  
  1092. #ifndef UXIII
  1093.     long n;
  1094. #endif
  1095.     if (ttyfd < 0) return(-1);        /* Not open. */
  1096.  
  1097.     ungotn = -1;            /* Initialize myread() stuff */
  1098.     inbufc = 0;
  1099.  
  1100. #ifdef aegis
  1101.     sio_$control((short)ttyfd, sio_$flush_in, true, st);
  1102.     if (st.all != status_$ok)
  1103.     {  fprintf(stderr, "flush failed: "); error_$print(st); }
  1104.     else {    /* sometimes the flush doesn't work */
  1105.     for (;;)
  1106.     {   char buf[256];
  1107.         /* eat all the characters that shouldn't be available */
  1108.         (void)ios_$get((short)ttyfd, ios_$cond_opt, buf, 256L, st);
  1109.         if (st.all == ios_$get_conditional_failed) break;
  1110.         fprintf(stderr, "flush failed(2): "); error_$print(st);
  1111.     }
  1112.     }
  1113. #else
  1114. #ifdef UXIII
  1115. #ifndef VXVE
  1116.     if (ioctl(ttyfd,TCFLSH,0) < 0) perror("flush failed");
  1117. #endif /* vxve */
  1118. #else
  1119. #ifdef TIOCFLUSH
  1120. #ifdef ANYBSD
  1121.     n = FREAD;                /* Specify read queue */
  1122.     if (ioctl(ttyfd,TIOCFLUSH,&n) < 0) perror("flush failed");
  1123. #else
  1124.     if (ioctl(ttyfd,TIOCFLUSH,0) < 0) perror("flush failed");
  1125. #endif
  1126. #endif
  1127. #endif
  1128. #endif
  1129.     return(0);
  1130. }
  1131.  
  1132. /* Interrupt Functions */
  1133.  
  1134.  
  1135. /* Timeout handler for communication line input functions */
  1136.  
  1137. timerh() {
  1138.     longjmp(sjbuf,1);
  1139. }
  1140.  
  1141.  
  1142. /* Set up terminal interrupts on console terminal */
  1143.  
  1144. #ifdef UXIII
  1145. esctrp() {                /* trap console escapes (^\) */
  1146.     conesc = 1;
  1147.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  1148. }
  1149. #endif
  1150.  
  1151. #ifdef V7
  1152. esctrp() {                /* trap console escapes (^\) */
  1153.     conesc = 1;
  1154.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  1155. }
  1156. #endif
  1157.  
  1158. #ifdef C70
  1159. esctrp() {                /* trap console escapes (^\) */
  1160.     conesc = 1;
  1161.     signal(SIGQUIT,SIG_IGN);        /* ignore until trapped */
  1162. }
  1163. #endif
  1164.  
  1165. /*  C O N I N T  --  Console Interrupt setter  */
  1166.  
  1167. conint(f) int (*f)(); {            /* Set an interrupt trap. */
  1168.     int x, y;
  1169. #ifdef SIGTSTP
  1170.     int stptrap();            /* Suspend trap */
  1171. #endif
  1172.  
  1173. /* Check for background operation, even if not running on real tty, so that */
  1174. /* background flag can be set correctly. */
  1175.  
  1176. #ifdef BSD4
  1177.     int mypgrp;                /* In BSD, we can check whether */
  1178.     int ctpgrp;                /* this process's group is the */
  1179.                     /* same as the controlling */
  1180.     mypgrp = getpgrp(0);        /* terminal's process group. */
  1181.     ioctl (1, TIOCGPGRP, &ctpgrp);
  1182.     x = (mypgrp != ctpgrp);        /* If they differ, then background. */
  1183.     debug(F101,"conint process group test","",x);
  1184. #else
  1185.     x = (signal(SIGINT,SIG_IGN) == SIG_IGN);
  1186.     debug(F101,"conint signal test","",x);
  1187. #endif
  1188.     y = isatty(0);
  1189.     debug(F101,"conint isatty test","",y);
  1190. #ifdef BSD29
  1191. /* For some reason the signal() test doesn't work under 2.9 BSD... */
  1192.     backgrd = !y;
  1193. #else
  1194.     backgrd = (x || !y);
  1195. #endif
  1196.     debug(F101,"conint backgrd","",backgrd);
  1197.  
  1198.     signal(SIGHUP,f);            /* Ensure lockfile cleared on hangup */
  1199.     signal(SIGTERM,f);            /* or soft kill. */
  1200.  
  1201. /* check if invoked in background -- if so signals set to be ignored */
  1202.  
  1203.     if (backgrd) {            /* In background, ignore signals */
  1204. #ifdef SIGTSTP
  1205.     signal(SIGTSTP,SIG_IGN);    /* Keyboard stop */
  1206. #endif
  1207.     signal(SIGQUIT,SIG_IGN);    /* Keyboard quit */
  1208.     signal(SIGINT,SIG_IGN);        /* Keyboard interrupt */
  1209.     } else {
  1210.     signal(SIGINT,f);        /* Catch terminal interrupt */
  1211. #ifdef SIGTSTP
  1212.     signal(SIGTSTP,stptrap);    /* Keyboard stop */
  1213. #endif
  1214. #ifdef UXIII
  1215.         signal(SIGQUIT,esctrp);        /* Quit signal, Sys III/V. */
  1216.     if (conesc) conesc = 0;        /* Clear out pending escapes */
  1217. #else
  1218. #ifdef V7
  1219.         signal(SIGQUIT,esctrp);        /* V7 like Sys III/V */
  1220.     if (conesc) conesc = 0;
  1221. #else
  1222. #ifdef aegis
  1223.         signal(SIGQUIT,f);        /* Apollo, catch it like others. */
  1224. #else
  1225.         signal(SIGQUIT,SIG_IGN);    /* Others, ignore like 4D & earlier. */
  1226. #endif
  1227. #endif
  1228. #endif
  1229.     conif = 1;            /* Flag console interrupts on. */
  1230.     }
  1231.     return;
  1232. }
  1233.  
  1234.  
  1235. /*  C O N N O I  --  Reset console terminal interrupts */
  1236.  
  1237. connoi() {                /* Console-no-interrupts */
  1238.  
  1239. #ifdef SIGTSTP
  1240.     signal(SIGTSTP,SIG_DFL);
  1241. #endif
  1242.     signal(SIGINT,SIG_DFL);
  1243.     signal(SIGHUP,SIG_DFL);
  1244.     signal(SIGQUIT,SIG_DFL);
  1245.     signal(SIGTERM,SIG_DFL);
  1246.     conif = 0;                /* Flag interrupt trapping off */
  1247. }
  1248.  
  1249. /*  myread() -- For use by systems that can do nonblocking read() calls  */
  1250. /*
  1251.  Returns:
  1252.   -1  if no characters available, timer expired
  1253.   -2  upon error (such as disconnect),
  1254.   otherwise value of character (0 or greater)
  1255. */
  1256. myread() {
  1257.     static int inbuf_item;
  1258.     static CHAR inbuf[257];
  1259.     CHAR readit;
  1260.  
  1261.     if (ungotn >= 0) {
  1262.     readit = ungotn;
  1263.     ungotn = -1;
  1264.     } else {
  1265.         if (inbufc > 0) {
  1266.         readit = inbuf[++inbuf_item];
  1267.         } else {
  1268. #ifdef aegis
  1269.     /* myread() returns -1 when no input is available.  All the users of */
  1270.     /* myread() explicitly loop until it returns a character or error. */
  1271.     /* The Apollo code waits for input to be available. */
  1272.  
  1273.     /* read in characters */
  1274.         inbufc = ios_$get((short)ttyfd, ios_$cond_opt, inbuf, 256L, st);
  1275.         errno = EIO;
  1276.         if (st.all == ios_$get_conditional_failed) /* get at least one */
  1277.         inbufc = ios_$get((short)ttyfd, 0, inbuf, 1L, st);
  1278.         if (st.all == ios_$end_of_file) inbufc = 0;
  1279.         else if (st.all != status_$ok)
  1280.         {   inbufc = -1; errno = EIO; }
  1281. #else
  1282.             inbufc = read(ttyfd,inbuf,256);
  1283.         if (inbufc > 0) {
  1284.         inbuf[inbufc] = '\0';
  1285.         debug(F101,"myread read","",inbufc);
  1286.         }
  1287. #endif /* aegis */
  1288.         if (inbufc == 0) {
  1289.         if (ttmdm) {
  1290.             debug(F101,"myread read=0, ttmdm","",ttmdm);
  1291.             errno = 9999;    /* magic number for no carrier */
  1292.             return(-2);        /* end of file has no errno */
  1293.         } else return(-1);    /* in sys 5 means no data available */
  1294.         }
  1295.         if (inbufc < 0) {        /* Real error */
  1296. #ifdef EWOULDBLOCK
  1297.         if (errno == EWOULDBLOCK) return(-1); else return(-2);
  1298. #else
  1299.         return(-2);
  1300. #endif /* ewouldblock */
  1301.             }
  1302.         readit = inbuf[inbuf_item = 0];
  1303.     }
  1304.         inbufc--;    
  1305.     }
  1306.     return(((int) readit) & 255);
  1307. }
  1308.  
  1309. myunrd(ch) CHAR ch; {            /* push back up to one character */
  1310.     ungotn = ch;
  1311. }
  1312.  
  1313. /*  I N I T R A W Q  --  Set up to read /DEV/KMEM for character count.  */
  1314.  
  1315. #ifdef    V7
  1316. /*
  1317.  Used in Version 7 to simulate Berkeley's FIONREAD ioctl call.  This
  1318.  eliminates blocking on a read, because we can read /dev/kmem to get the
  1319.  number of characters available for raw input.  If your system can't
  1320.  or you won't let it read /dev/kmem (the world that is) then you must
  1321.  figure out a different way to do the counting of characters available,
  1322.  or else replace this by a dummy function that always returns 0.
  1323. */
  1324. /*
  1325.  * Call this routine as: initrawq(tty)
  1326.  * where tty is the file descriptor of a terminal.  It will return
  1327.  * (as a char *) the kernel-mode memory address of the rawq character
  1328.  * count, which may then be read.  It has the side-effect of flushing
  1329.  * input on the terminal.
  1330.  */
  1331. /*
  1332.  * John Mackin, Physiology Dept., University of Sydney (Australia)
  1333.  * ...!decvax!mulga!physiol.su.oz!john
  1334.  *
  1335.  * Permission is hereby granted to do anything with this code, as
  1336.  * long as this comment is retained unmodified and no commercial
  1337.  * advantage is gained.
  1338.  */
  1339. #include <a.out.h>
  1340. #include <sys/proc.h>
  1341.  
  1342. char *initrawq(tty) int tty; {
  1343. #ifdef UTS24
  1344.     return(0);
  1345. #else
  1346. #ifdef BSD29
  1347.     return(0);
  1348. #else
  1349.     long lseek();
  1350.     static struct nlist nl[] = {
  1351.     {PROCNAME},
  1352.     {NPROCNAME},
  1353.     {""}
  1354.     };
  1355.     static struct proc *pp;
  1356.     char *malloc(), *qaddr, *p, c;
  1357.     int m, pid, me;
  1358.     NPTYPE xproc;            /* Its type is defined in makefile. */
  1359.     int catch();
  1360.  
  1361.     me = getpid();
  1362.     if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
  1363.     nlist(BOOTNAME, nl);
  1364.     if (nl[0].n_type == 0) err("proc array");
  1365.  
  1366.     if (nl[1].n_type == 0) err("nproc");
  1367.  
  1368.     lseek(m, (long)(nl[1].n_value), 0);
  1369.     read (m, &xproc, sizeof(xproc));
  1370.     signal(SIGALRM, catch);
  1371.     if ((pid = fork()) == 0) {
  1372.     while(1)
  1373.         read(tty, &c, 1);
  1374.     }
  1375.     alarm(2);
  1376.  
  1377.     if(setjmp(jjbuf) == 0) {
  1378.     while(1)
  1379.         read(tty, &c, 1);
  1380.     }
  1381.     signal(SIGALRM, SIG_DFL);
  1382.  
  1383. #ifdef DIRECT
  1384.     pp = (struct proc *) nl[0].n_value;
  1385. #else
  1386.     if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
  1387.     if (read(m, &pp, sizeof(pp)) != sizeof(pp))  err("no read of proc ptr");
  1388. #endif
  1389.     lseek(m, (long)(nl[1].n_value), 0);
  1390.     read(m, &xproc, sizeof(xproc));
  1391.  
  1392.     if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
  1393.     if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
  1394.     if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
  1395.         err("read proc table");
  1396.     for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
  1397.     if (pp -> p_pid == (short) pid) goto iout;
  1398.     }
  1399.     err("no such proc");
  1400.  
  1401. iout:
  1402.     close(m);
  1403.     qaddr = (char *)(pp -> p_wchan);
  1404.     free (p);
  1405.     kill(pid, SIGKILL);
  1406.     wait((int *)0);        /* Destroy the ZOMBIEs! */
  1407.     return (qaddr);
  1408. #endif
  1409. #endif
  1410. }
  1411.  
  1412. /*  More V7-support functions...  */
  1413.  
  1414. static
  1415. err(s) char *s; {
  1416.     char buf[200];
  1417.  
  1418.     sprintf(buf, "fatal error in initrawq: %s", s);
  1419.     perror(buf);
  1420.     doexit(1);
  1421. }
  1422.  
  1423. static
  1424. catch() {
  1425.     longjmp(jjbuf, -1);
  1426. }
  1427.  
  1428.  
  1429. /*  G E N B R K  --  Simulate a modem break.  */
  1430.  
  1431. #define    BSPEED    B150
  1432.  
  1433. genbrk(fn) int fn; {
  1434.     struct sgttyb ttbuf;
  1435.     int ret, sospeed;
  1436.  
  1437.     ret = ioctl(fn, TIOCGETP, &ttbuf);
  1438.     sospeed = ttbuf.sg_ospeed;
  1439.     ttbuf.sg_ospeed = BSPEED;
  1440.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  1441.     ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", 8);
  1442.     ttbuf.sg_ospeed = sospeed;
  1443.     ret = ioctl(fn, TIOCSETP, &ttbuf);
  1444.     ret = write(fn, "@", 1);
  1445.     return;
  1446. }
  1447. #endif
  1448.  
  1449. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  1450.  
  1451. ttchk() {
  1452.     int x; long n;
  1453. #ifdef FIONREAD
  1454.     x = ioctl(ttyfd, FIONREAD, &n);    /* Berkeley and maybe some others */
  1455.     debug(F101,"ttchk","",n);
  1456.     return((x < 0) ? 0 : n);
  1457. #else
  1458. #ifdef    V7
  1459.     lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
  1460.     x = read(kmem[TTY], &n, sizeof(int));
  1461.     return((x == sizeof(int))? n: 0);
  1462. #else
  1463. #ifdef UXIII
  1464.     return(inbufc + (ungotn >= 0) );    /* Sys III, Sys V */
  1465. #else
  1466. #ifdef PROVX1
  1467.     x = ioctl(ttyfd, TIOCQCNT, &ttbuf);    /* Pro/3xx Venix V.1 */
  1468.     n = ttbuf.sg_ispeed & 0377;
  1469.     return((x < 0) ? 0 : n);
  1470. #else
  1471. #ifdef aegis
  1472.     return(inbufc + (ungotn >= 0) );    /* Apollo Aegis */
  1473. #else
  1474. #ifdef C70
  1475.     return(inbufc + (ungotn >= 0) );    /* etc... */
  1476. #else
  1477.     return(0);
  1478. #endif
  1479. #endif
  1480. #endif
  1481. #endif
  1482. #endif
  1483. #endif
  1484. }
  1485.  
  1486.  
  1487. /*  T T X I N  --  Get n characters from tty input buffer  */
  1488.  
  1489. /*  Returns number of characters actually gotten, or -1 on failure  */
  1490.  
  1491. /*  Intended for use only when it is known that n characters are actually */
  1492. /*  Available in the input buffer.  */
  1493.  
  1494. ttxin(n,buf) int n; char *buf; {
  1495.     int x;
  1496.  
  1497. #ifdef MYREAD
  1498.     for( x = 0; (x > -1) && (x < n); buf[x++] = myread() );
  1499. #else
  1500.     debug(F101,"ttxin: n","",n);
  1501.     x = read(ttyfd,buf,n);
  1502.     debug(F101," x","",x);
  1503. #endif
  1504.     if (x > 0) buf[x] = '\0';
  1505.     if (x < 0) x = -1;
  1506.     return(x);
  1507. }
  1508.  
  1509. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  1510.  
  1511. ttol(s,n) int n; char *s; {
  1512.     int x;
  1513.     if (ttyfd < 0) return(-1);        /* Not open. */
  1514.     x = write(ttyfd,s,n);
  1515.     debug(F111,"ttol",s,n);
  1516.     if (x < 0) debug(F101,"ttol failed","",x);
  1517.     return(x);
  1518. }
  1519.  
  1520.  
  1521. /*  T T O C  --  Output a character to the communication line  */
  1522.  
  1523. ttoc(c) char c; {
  1524.     if (ttyfd < 0) return(-1);        /* Not open. */
  1525.     return(write(ttyfd,&c,1));
  1526. }
  1527.  
  1528. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1529. /*
  1530.   If no break character encountered within "max", return "max" characters,
  1531.   with disposition of any remaining characters undefined.  Otherwise, return
  1532.   the characters that were read, including the break character, in "dest" and
  1533.   the number of characters read as the value of the function, or 0 upon end of
  1534.   file, or -1 if an error occurred.  Times out & returns error if not completed
  1535.   within "timo" seconds.
  1536. */
  1537. #define CTRLC '\03'
  1538. ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol; {
  1539.     int x = 0, ccn = 0, c, i, j, m, n;    /* local variables */
  1540.  
  1541.     if (ttyfd < 0) return(-1);        /* Not open. */
  1542.  
  1543.     m = (ttprty) ? 0177 : 0377;        /* Parity stripping mask. */
  1544.     *dest = '\0';            /* Clear destination buffer */
  1545.     if (timo) signal(SIGALRM,timerh);    /* Enable timer interrupt */
  1546.     alarm(timo);            /* Set it. */
  1547.     if (setjmp(sjbuf)) {        /* Timer went off? */
  1548.         x = -1;
  1549.     } else {
  1550.     i = 0;                /* Next char to process */
  1551.     j = 0;                /* Buffer position */
  1552.         while (1) {
  1553.             if ((n = ttchk()) > 0) {    /* See how many chars have arrived */
  1554.                 if (n > (max - j)) n = max - j;
  1555.                 if ((n = ttxin(n,dest+i)) < 0) { /* Get them all at once */
  1556.             x = -1;
  1557.             break;
  1558.         }
  1559.         } else {            /* Or else... */
  1560.         n = 1;            /* just wait for a char */
  1561.         if ((c = ttinc(0)) == -1) {
  1562.             x = -1;
  1563.             break;
  1564.         }
  1565.                 dest[i] = c;        /* Got one. */
  1566.         }
  1567.         j = i + n;            /* Remember next buffer position. */
  1568.         if (j >= max) {
  1569.         debug(F101,"ttinl buffer overflow","",j);
  1570.         x = -1;
  1571.         break;
  1572.         }
  1573.         for (i; i < j; i++) {    /* Go thru all chars we just got */
  1574.         dest[i] &= m;        /* Strip any parity */
  1575.             if (dest[i] == eol) {    /* Got eol? */
  1576.           dest[++i] = '\0';    /* Yes, tie off string, */
  1577.           alarm(0);        /* turn off timers, etc, */
  1578.           if (timo) signal(SIGALRM,SIG_DFL); /* and return length. */
  1579.           return(i);
  1580.           } else if ((dest[i] & 0177) == CTRLC) { /* Check for ^C^C */
  1581.           if (++ccn > 1) {    /* If we got 2 in a row, clean up */
  1582.              alarm(0);        /* and exit. */
  1583.              signal(SIGALRM,SIG_DFL);
  1584.              fprintf(stderr,"^C...");
  1585.              ttres();
  1586.              fprintf(stderr,"\n");
  1587.              return(-2);
  1588.           }
  1589.           } else ccn = 0;    /* Not ^C, so reset ^C counter, */
  1590.       }
  1591.     }
  1592.     }
  1593.     debug(F100,"ttinl timout","",0);    /* Get here on timeout. */
  1594.     debug(F111," with",dest,i);
  1595.     alarm(0);                /* Turn off timer */
  1596.     signal(SIGALRM,SIG_DFL);        /* and interrupt, */
  1597.     return(x);                /* and return error code. */
  1598. }
  1599.  
  1600. /*  T T I N C --  Read a character from the communication line  */
  1601.  
  1602. ttinc(timo) int timo; {
  1603.     int m, n = 0;
  1604.     CHAR ch = 0;
  1605.  
  1606.     m = (ttprty) ? 0177 : 0377;        /* Parity stripping mask. */
  1607.     if (ttyfd < 0) return(-1);        /* Not open. */
  1608.     if (timo <= 0) {            /* Untimed. */
  1609. #ifdef MYREAD
  1610.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  1611.         while ((n = myread()) == -1) ;    /* Wait for a character... */
  1612.     if (n == -2) n++;
  1613.     return( (n < 0) ? -1 : n & m );
  1614. #else
  1615.     while ((n = read(ttyfd,&ch,1)) == 0) ; /* Wait for a character. */
  1616.     return( (n < 0) ? -1 : (ch & 0377) );
  1617. #endif
  1618.     }
  1619.     signal(SIGALRM,timerh);        /* Timed, set up timer. */
  1620.     alarm(timo);
  1621.     if (setjmp(sjbuf)) {
  1622.     n = -1;
  1623.     } else {
  1624. #ifdef MYREAD
  1625.         while ((n = myread()) == -1) ;    /* If managing own buffer... */
  1626.     if (n == -2) {
  1627.         n++;
  1628.     } else {
  1629.         ch = n;
  1630.         n = 1;    
  1631.     }
  1632. #else
  1633.         n = read(ttyfd,&ch,1);        /* Otherwise call the system. */
  1634. #endif
  1635.     }
  1636.     alarm(0);                /* Turn off timer, */
  1637.     signal(SIGALRM,SIG_DFL);        /* and interrupt. */
  1638.     return( (n < 0) ? -1 : (ch & m) );  /* Return char or -1. */
  1639. }
  1640.  
  1641. /*  T T S N D B  --  Send a BREAK signal  */
  1642.  
  1643. ttsndb() {
  1644.     int x; long n; char spd;
  1645.  
  1646.     if (ttyfd < 0) return(-1);        /* Not open. */
  1647.  
  1648. #ifdef PROVX1
  1649.     gtty(ttyfd,&ttbuf);            /* Get current tty flags */
  1650.     spd = ttbuf.sg_ospeed;        /* Save speed */
  1651.     ttbuf.sg_ospeed = B50;        /* Change to 50 baud */
  1652.     stty(ttyfd,&ttbuf);            /*  ... */
  1653.     write(ttyfd,brnuls,3);        /* Send 3 nulls */
  1654.     ttbuf.sg_ospeed = spd;        /* Restore speed */
  1655.     stty(ttyfd,&ttbuf);            /*  ... */
  1656.     return(0);
  1657. #else
  1658. #ifdef aegis
  1659.     sio_$control((short)ttyfd, sio_$send_break, 250, st);
  1660.     return(0);
  1661. #else
  1662. #ifdef UXIII
  1663.     if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) {    /* Send a BREAK */
  1664.         perror("Can't send BREAK");
  1665.     return(-1);
  1666.     }
  1667.     return(0);
  1668. #else
  1669. #ifdef ANYBSD
  1670.     n = FWRITE;                /* Flush output queue. */
  1671.     ioctl(ttyfd,TIOCFLUSH,&n);         /* Ignore any errors.. */
  1672.     if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) {    /* Turn on BREAK */
  1673.         perror("Can't send BREAK");
  1674.     return(-1);
  1675.     }
  1676.     x = msleep(275);            /* Sleep for so many milliseconds */
  1677.     if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) {    /* Turn off BREAK */
  1678.     perror("BREAK stuck!!!");
  1679.     doexit(1);            /* Get out, closing the line. */
  1680.                     /*   with exit status = 1 */
  1681.     }
  1682.     return(x);
  1683. #else
  1684. #ifdef    V7
  1685.     genbrk(ttyfd);            /* Simulate a BREAK */
  1686.     return(x);
  1687. #endif
  1688. #endif
  1689. #endif
  1690. #endif
  1691. #endif
  1692. }
  1693.  
  1694. /*  M S L E E P  --  Millisecond version of sleep().  */
  1695.  
  1696. /*
  1697.  Intended only for small intervals.  For big ones, just use sleep().
  1698. */
  1699.  
  1700. msleep(m) int m; {
  1701.  
  1702. #ifdef aegis
  1703.     time_$clock_t dur;
  1704.  
  1705.     dur.c2.high16 = 0;
  1706.     dur.c2.low32  = 250 * m; /* one millisecond = 250 four microsecond ticks */
  1707.     time_$wait(time_$relative, dur, st);
  1708.     return(0);
  1709. #else
  1710. #ifdef PROVX1
  1711.     if (m <= 0) return(0);
  1712.     sleep(-((m * 60 + 500) / 1000));
  1713.     return(0);
  1714. #endif
  1715.  
  1716. #ifdef ANYBSD
  1717.     int t1, t3, t4;
  1718.     if (m <= 0) return(0);
  1719. #ifndef BSD42
  1720. /* 2.9 and 4.1 BSD do it this way */
  1721.     if (ftime(&ftp) < 0) return(-1);    /* Get current time. */
  1722.     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
  1723.     while (1) {
  1724.     ftime(&ftp);            /* new time */
  1725.     t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
  1726.     if (t3 > m) return(t3);
  1727.     }
  1728. #else
  1729. /* 4.2 & above can do it with select()... */
  1730.     if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */
  1731.     t1 = tv.tv_sec;            /* Seconds */
  1732.  
  1733.     tv.tv_sec = 0;            /* Use select() */
  1734.     tv.tv_usec = m * 1000;
  1735.     return(select( 0, (int *)0, (int *)0, (int *)0, &tv) );
  1736. #endif
  1737. #endif
  1738.  
  1739. /* The clock-tick business is a pain.  Wm. E. Davidsen suggested: */
  1740. /*   #include <sys/param.h>      */
  1741. /*   #define CLOCK_TICK 1000/HZ  */
  1742. /* But I don't see the symbol HZ in this file on my VAX. */
  1743. /* Maybe just for XENIX. */
  1744.  
  1745. #ifdef UXIII
  1746. #ifdef XENIX
  1747. /* Actually, watch out.  It's 50 on the AT, 20 on older PCs... */
  1748. #define CLOCK_TICK 50            /* millisecs per clock tick */
  1749. #else
  1750. #ifndef XENIX
  1751. #define CLOCK_TICK 17            /* 1/60 sec */
  1752. #endif
  1753. #endif
  1754.  
  1755.     extern long times();
  1756.     long t1, t2, tarray[4];
  1757.     int t3;
  1758.  
  1759. /* In SCO Xenix 2.1.3 or later, you can use nap((long)m) to do this. */
  1760.  
  1761.     if (m <= 0) return(0);
  1762.     if ((t1 = times(tarray)) < 0) return(-1);
  1763.     while (1) {
  1764.     if ((t2 = times(tarray)) < 0) return(-1);
  1765.     t3 = ((int)(t2 - t1)) * CLOCK_TICK;
  1766.     if (t3 > m) return(t3);
  1767.     }
  1768. #endif
  1769.  
  1770. #ifdef TOWER1
  1771.     int t1, t3;
  1772.     if (m <= 0) return(0);
  1773.     if (ftime(&ftp) < 0) return(-1);        /* Get current time. */
  1774.     t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
  1775.     while (1) {
  1776.     ftime(&ftp);                /* new time */
  1777.     t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
  1778.     if (t3 > m) return (t3);
  1779.     }
  1780. #endif
  1781. #endif
  1782. }
  1783.  
  1784. /*  R T I M E R --  Reset elapsed time counter  */
  1785.  
  1786. rtimer() {
  1787.     tcount = time( (long *) 0 );
  1788. }
  1789.  
  1790.  
  1791. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1792.  
  1793. gtimer() {
  1794.     int x;
  1795.     x = (int) (time( (long *) 0 ) - tcount);
  1796.     rtimer();
  1797.     return( (x < 0) ? 0 : x );
  1798. }
  1799.  
  1800.  
  1801. /*  Z T I M E  --  Return date/time string  */
  1802.  
  1803. ztime(s) char **s; {
  1804.  
  1805. #ifdef UXIII
  1806.     extern long time();            /* Sys III/V way to do it */
  1807.     char *ctime();
  1808.     long clock_storage;
  1809.  
  1810.     clock_storage = time( (long *) 0 );
  1811.     *s = ctime( &clock_storage );
  1812. #endif
  1813.  
  1814. #ifdef PROVX1
  1815.     int utime[2];            /* Venix way */
  1816.     time(utime);
  1817.     *s = ctime(utime);
  1818. #endif
  1819.  
  1820. #ifdef ANYBSD
  1821.     char *asctime();            /* Berkeley way */
  1822.     struct tm *localtime();
  1823.     struct tm *tp;
  1824. #ifdef BSD42
  1825.     gettimeofday(&tv, &tz);        /* BSD 4.2 */
  1826.     time(&tv.tv_sec);
  1827.     tp = localtime(&tv.tv_sec);
  1828. #else
  1829.     time(&clock);            /* BSD 4.1, 2.9 ... ceb */
  1830.     tp = localtime(&clock);
  1831. #endif
  1832.     *s = asctime(tp);
  1833. #endif
  1834.  
  1835. #ifdef TOWER1
  1836.     char *asctime();            /* Tower way */
  1837.     struct tm *localtime();
  1838.     struct tm *tp;
  1839.  
  1840.     time(&clock);
  1841.     tp = localtime(&clock);
  1842.     *s = asctime(tp);
  1843. #endif
  1844. #ifdef V7
  1845.     char *asctime();            /* V7 way */
  1846.     struct tm *localtime();
  1847.     struct tm *tp;
  1848.  
  1849.     time(&clock);
  1850.     tp = localtime(&clock);
  1851.     *s = asctime(tp);
  1852. #endif
  1853. }
  1854.  
  1855. /*  C O N G M  --  Get console terminal modes.  */
  1856.  
  1857. /*
  1858.  Saves current console mode, and establishes variables for switching between
  1859.  current (presumably normal) mode and other modes.
  1860. */
  1861.  
  1862. congm() {
  1863.     if (!isatty(0)) return(0);        /* only for real ttys */
  1864. #ifdef aegis
  1865.     ios_$inq_type_uid(ios_$stdin, conuid, st);
  1866.     if (st.all != status_$ok)
  1867.     {  fprintf(stderr, "problem getting stdin objtype: "); error_$print(st); }
  1868.     concrp = (conuid == mbx_$uid);
  1869.     conbufn = 0;
  1870. #endif
  1871. #ifndef UXIII
  1872.      gtty(0,&ccold);            /* Structure for restoring */
  1873.      gtty(0,&cccbrk);            /* For setting CBREAK mode */
  1874.      gtty(0,&ccraw);            /* For setting RAW mode */
  1875. #else
  1876.      ioctl(0,TCGETA,&ccold);
  1877.      ioctl(0,TCGETA,&cccbrk);
  1878.      ioctl(0,TCGETA,&ccraw);
  1879. #endif
  1880. #ifdef VXVE
  1881.      cccbrk.c_line = 0;            /* STTY line 0 for CDC VX/VE */
  1882.      ioctl(0,TCSETA,&cccbrk);
  1883.      ccraw.c_line = 0;            /* STTY line 0 for CDC VX/VE */
  1884.      ioctl(0,TCSETA,&ccraw);
  1885. #endif /* vxve */
  1886.      cgmf = 1;                /* Flag that we got them. */
  1887.      return(0);
  1888. }
  1889.  
  1890.  
  1891. /*  C O N C B --  Put console in cbreak mode.  */
  1892.  
  1893. /*  Returns 0 if ok, -1 if not  */
  1894.  
  1895. concb(esc) char esc; {
  1896.     int x;
  1897.     if (!isatty(0)) return(0);        /* only for real ttys */
  1898.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  1899.     escchr = esc;            /* Make this available to other fns */
  1900.     ckxech = 1;                /* Program can echo characters */
  1901. #ifdef aegis
  1902.     conbufn = 0;
  1903.     if (concrp) return(write(1, "\035\002", 2));
  1904.     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
  1905. #endif
  1906. #ifndef UXIII
  1907.     cccbrk.sg_flags |= CBREAK;        /* Set to character wakeup, */
  1908.     cccbrk.sg_flags &= ~ECHO;        /* no echo. */
  1909.     x = stty(0,&cccbrk);
  1910. #else
  1911.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  1912.     cccbrk.c_cc[0] = 003;        /* interrupt char is control-c */
  1913.     cccbrk.c_cc[1] = escchr;        /* escape during packet modes */
  1914.     cccbrk.c_cc[4] = 1;
  1915. #ifdef ZILOG
  1916.     cccbrk.c_cc[5] = 0;
  1917. #else
  1918.     cccbrk.c_cc[5] = 1;
  1919. #endif /* zilog */
  1920.     x = ioctl(0,TCSETAW,&cccbrk);      /* set new modes . */
  1921. #endif
  1922.  
  1923. #ifndef aegis
  1924.     if (x > -1) setbuf(stdout,NULL);    /* Make console unbuffered. */
  1925. #endif
  1926. #ifdef    V7
  1927.     if (kmem[CON] < 0) {
  1928.     qaddr[CON] = initrawq(0);
  1929.     if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
  1930.         fprintf(stderr, "Can't read /dev/kmem in concb.\n");
  1931.         perror("/dev/kmem");
  1932.         exit(1);
  1933.     }
  1934.     }
  1935. #endif
  1936.     return(x);
  1937. }
  1938.  
  1939. /*  C O N B I N  --  Put console in binary mode  */
  1940.  
  1941. /*  Returns 0 if ok, -1 if not  */
  1942.  
  1943. conbin(esc) char esc; {
  1944.     if (!isatty(0)) return(0);        /* only for real ttys */
  1945.     if (cgmf == 0) congm();        /* Get modes if necessary. */
  1946.     escchr = esc;            /* Make this available to other fns */
  1947.     ckxech = 1;                /* Program can echo characters */
  1948. #ifdef aegis
  1949.     conbufn = 0; if (concrp) return(write(1, "\035\002", 2));
  1950.     if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
  1951. #endif
  1952. #ifndef UXIII
  1953.     ccraw.sg_flags |= (RAW|TANDEM);       /* Set rawmode, XON/XOFF */
  1954.     ccraw.sg_flags &= ~(ECHO|CRMOD);      /* Set char wakeup, no echo */
  1955.     return(stty(0,&ccraw));
  1956. #else
  1957.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  1958.     ccraw.c_iflag |= (BRKINT|IGNPAR);
  1959.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
  1960.             |INPCK|ISTRIP);
  1961.     ccraw.c_oflag &= ~OPOST;
  1962.  
  1963. /*** Kermit used to put the console in 8-bit raw mode, but some users have
  1964.  *** pointed out that this should not be done, since some sites actually
  1965.  *** use terminals with parity settings on their Unix systems, and if we
  1966.  *** override the current settings and stop doing parity, then their terminals
  1967.  *** will display blotches for characters whose parity is wrong.  Therefore,
  1968.  *** the following two lines are commented out (Larry Afrin, Clemson U):
  1969.  ***
  1970.  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
  1971.  ***   ccraw.c_cflag |= (CS8|CREAD);
  1972.  ***
  1973.  *** Sys III/V sites that have trouble with this can restore these lines.
  1974.  ***/
  1975.     ccraw.c_cc[4] = 1;
  1976.     ccraw.c_cc[5] = 1;
  1977.     return(ioctl(0,TCSETAW,&ccraw) );      /* set new modes . */
  1978. #endif
  1979. }
  1980.  
  1981.  
  1982. /*  C O N R E S  --  Restore the console terminal  */
  1983.  
  1984. conres() {
  1985.     if (cgmf == 0) return(0);        /* Don't do anything if modes */
  1986.     if (!isatty(0)) return(0);        /* only for real ttys */
  1987. #ifndef UXIII                /* except for sIII, */
  1988.     sleep(1);                /*  not known! */
  1989. #endif                    /*   (sIII does wait in ioctls) */
  1990.     ckxech = 0;                /* System should echo chars */
  1991. #ifdef aegis
  1992.     conbufn = 0; if (concrp) return(write(1, "\035\001", 2));
  1993.     if (conuid == input_pad_$uid) {pad_$cooked(ios_$stdin, st); return(0);}
  1994. #endif
  1995. #ifndef UXIII
  1996.     return(stty(0,&ccold));        /* Restore controlling tty */
  1997. #else
  1998.     return(ioctl(0,TCSETAW,&ccold));
  1999. #endif
  2000. }
  2001.  
  2002. /*  C O N O C  --  Output a character to the console terminal  */
  2003.  
  2004. conoc(c) char c; {
  2005.     write(1,&c,1);
  2006. }
  2007.  
  2008. /*  C O N X O  --  Write x characters to the console terminal  */
  2009.  
  2010. conxo(x,s) char *s; int x; {
  2011.     write(1,s,x);
  2012. }
  2013.  
  2014. /*  C O N O L  --  Write a line to the console terminal  */
  2015.  
  2016. conol(s) char *s; {
  2017.     int len;
  2018.     len = strlen(s);
  2019.     write(1,s,len);
  2020. }
  2021.  
  2022. /*  C O N O L A  --  Write an array of lines to the console terminal */
  2023.  
  2024. conola(s) char *s[]; {
  2025.     int i;
  2026.     for (i=0 ; *s[i] ; i++) conol(s[i]);
  2027. }
  2028.  
  2029. /*  C O N O L L  --  Output a string followed by CRLF  */
  2030.  
  2031. conoll(s) char *s; {
  2032.     conol(s);
  2033.     write(1,"\r\n",2);
  2034. }
  2035.  
  2036. /*  C O N C H K  --  Return how many characters available at console  */
  2037.  
  2038. conchk() {
  2039.     int x; long n;
  2040.  
  2041. #ifdef PROVX1
  2042.     x = ioctl(0, TIOCQCNT, &ttbuf);
  2043.     n = ttbuf.sg_ispeed & 0377;
  2044.     return((x < 0) ? 0 : n);
  2045. #else
  2046. #ifdef aegis
  2047.     if (conbufn > 0) return(conbufn);    /* use old count if nonzero */
  2048.  
  2049.     /* read in more characters */
  2050.     conbufn = ios_$get(ios_$stdin,
  2051.           ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
  2052.     if (st.all != status_$ok) conbufn = 0;
  2053.     conbufp = conbuf;
  2054.     return(conbufn);
  2055. #else
  2056. #ifdef V7
  2057.     lseek(kmem[CON], (long) qaddr[CON], 0);
  2058.     x = read(kmem[CON], &n, sizeof(int));
  2059.     return((x == sizeof(int))? n: 0);
  2060. #else
  2061. #ifdef UXIII
  2062.     if (conesc) {            /* Escape typed */
  2063.     conesc = 0;
  2064.     signal(SIGQUIT,esctrp);        /* Restore escape */
  2065.     return(1);
  2066.     }
  2067.     return(0);
  2068. #else
  2069. #ifdef C70
  2070.     if (conesc) {            /* Escape typed */
  2071.     conesc = 0;
  2072.     signal(SIGQUIT,esctrp);        /* Restore escape */
  2073.     return(1);
  2074.     }
  2075.     return(0);
  2076. #else
  2077. #ifdef FIONREAD
  2078.     x = ioctl(0, FIONREAD, &n);        /* BSD and maybe some others */
  2079.     return((x < 0) ? 0 : n);
  2080. #else
  2081.     return(0);                /* Others can't do. */
  2082. #endif
  2083. #endif
  2084. #endif
  2085. #endif
  2086. #endif
  2087. #endif
  2088. }
  2089.  
  2090. /*  C O N I N C  --  Get a character from the console  */
  2091.  
  2092. coninc(timo) int timo; {
  2093.     int n = 0; char ch;
  2094. #ifdef aegis
  2095.     fflush(stdout);
  2096.     if (conchk() > 0)
  2097.     {  --conbufn; return(*conbufp++ & 0377); }
  2098. #endif
  2099.     if (timo <= 0 ) {            /* untimed */
  2100.     n = read(0, &ch, 1);        /* Read a character. */
  2101.     ch &= 0377;
  2102.     if (n > 0) return(ch);         /* Return the char if read */
  2103.     else
  2104. #ifdef UXIII
  2105. #ifndef CIE                /* CIE Regulus has no such symbol */
  2106.         if (n < 0 && errno == EINTR) /* if read was interrupted by QUIT */
  2107.         return(escchr);         /* user entered escape character */
  2108.         else            /* couldnt be ^c, sigint never returns */
  2109. #endif
  2110. #endif
  2111.         return(-1);          /* Return the char, or -1. */
  2112.     }
  2113.     signal(SIGALRM,timerh);        /* Timed read, so set up timer */
  2114.     alarm(timo);
  2115.     if (setjmp(sjbuf)) n = -2;
  2116.     else {
  2117.     n = read(0, &ch, 1);
  2118.     ch &= 0377;
  2119.     }
  2120.     alarm(0);                /* Stop timing, we got our character */
  2121.     signal(SIGALRM,SIG_DFL);
  2122.     if (n > 0) return(ch);
  2123.     else
  2124. #ifdef UXIII
  2125. #ifndef CIE                /* CIE Regulus has no such symbol */
  2126.         if (n == -1 && errno == EINTR)  /* If read interrupted by QUIT, */
  2127.         return(escchr);        /* user entered escape character, */
  2128.         else                    /* can't be ^c, sigint never returns */
  2129. #endif
  2130. #endif
  2131.     return(-1);
  2132. }
  2133.  
  2134. #ifdef ATT7300
  2135. #include <sys/phone.h>
  2136. #include <dial.h>
  2137. #define ATT7300 4            /* REH */
  2138. CALL tcfig;
  2139. struct termio ctermio = {0};
  2140. struct updata ph;
  2141. static int att7300 = 0;            /* REH */
  2142.  
  2143. /*  A T T D I A L  --  Dial up the remote system */
  2144.  
  2145. /* Purpose: to open and dial a number on the internal modem available on the
  2146.  * ATT7300 UNIX PC.  Richard E. Hill, Dickinson, TX.
  2147.  */
  2148.  
  2149. attdial(ttname,speed,telnbr) char *ttname,*telnbr; int speed; {
  2150.     int err;
  2151.  
  2152.     if (ttyfd > 0) {
  2153.     ioctl(ttyfd,TCGETA,&ctermio);    /* save current settings */
  2154.     err=ttclos();            /* close port */
  2155.     } else ioctl(0,TCGETA,&ctermio);    /* get standard settings */
  2156.  
  2157. /* Open line, check availability & data mode, turn on speaker, close port. */
  2158.  
  2159.     ttyfd = open (ttname,O_RDWR | O_NDELAY);
  2160.     if (err=ioctl(ttyfd,PIOCOFFHOOK,&ph)) {
  2161.     printf("Phone line for %s not available:%d %d %d\n",
  2162.            ttname,ttyfd,err,errno);
  2163.     close(ttyfd);
  2164.     ttyfd = -1;
  2165.     return(-1);
  2166.     }
  2167.     ioctl(ttyfd,PIOCGETP,&ph);     /* set phone parameters   */
  2168.     if (ph.c_lineparam & VOICE) {
  2169.     printf("Phone line %s not in data mode. Switch to data & redial\n",
  2170.            ttname);
  2171.     ioctl(ttyfd,PIOCDISC,&ph);
  2172.     close(ttyfd);
  2173.     ttyfd = -1;
  2174.       return(-1);
  2175.     }
  2176.     ph.c_feedback |= (SPEAKERON | RINGON | NORMSPK);
  2177.     ioctl(ttyfd,PIOCSETP,&ph);        /* set phone parameters   */
  2178.     ioctl(ttyfd,PIOCDISC,&ph);        /* release phone resources for dial */
  2179.     close(ttyfd);
  2180. /*
  2181.     fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
  2182. line_status:%o feedback:%o\n",
  2183.         ph.c_lineparam, ph.c_waitdialtone, ph.c_linestatus,ph.c_feedback);
  2184. */
  2185.  
  2186. /*  Close line so that it can be reopened using system routine "dial". */
  2187. /*  Set terminal configuration parameters. */
  2188.  
  2189.     ctermio.c_iflag |= (BRKINT|IGNPAR|IXON|IXOFF);
  2190.     ctermio.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP| IXANY);
  2191.     ctermio.c_oflag &= ~OPOST;
  2192.     ctermio.c_cflag = (B1200 | CS8 | CREAD | CLOCAL | HUPCL);
  2193.     ctermio.c_lflag &= ~(ICANON|ECHO);
  2194.     ctermio.c_cc[4] = 1;
  2195.     ctermio.c_cc[5] = 0;
  2196.     tcfig.attr = &ctermio;
  2197.     tcfig.baud = speed <= 1200 ? speed : 1200;
  2198.     tcfig.speed = speed <= 300 ? 300 : 1200;
  2199.     tcfig.line = ttname;
  2200.     tcfig.telno = telnbr;
  2201.     tcfig.modem = 0;
  2202.     fprintf (stderr,"dialing:%s on line:%s at %d baud, speed:%d\n",
  2203.          tcfig.telno,tcfig.line,tcfig.baud,tcfig.speed);
  2204.     if ((ttyfd = dial(tcfig)) > 0) {
  2205.     att7300 = 1;
  2206. /*
  2207.     ioctl(ttyfd,TCGETA,&ctermio);
  2208.     fprintf(stderr,"after dial:iflag:%o, oflag:%o, cflag:%o, lflag:%o,\
  2209.     line:%o\n", ctermio.c_iflag,ctermio.c_oflag,ctermio.c_cflag,
  2210.     ctermio.c_lflag, ctermio.c_line);
  2211. */
  2212.     return(0);
  2213.     }
  2214.     printf("Sorry, connection not made. Error status: %d\n",ttyfd);
  2215.     return(-2);
  2216. }
  2217. #endif /* ATT7300 */
  2218.  
  2219.  
  2220.